package com.yanqu.road.server.manager.union.huaben;

import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.cross.LogUnionHuaBenAttack;
import com.yanqu.road.entity.log.cross.LogUnionHuaBenLevelPass;
import com.yanqu.road.entity.log.cross.LogUnionHuaBenOpen;
import com.yanqu.road.entity.log.cross.LogUnionHuaBenPingJia;
import com.yanqu.road.entity.rank.cross.CrossUnionWeekRank;
import com.yanqu.road.entity.union.cross.CrossUnionInfo;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.entity.union.huaben.*;
import com.yanqu.road.logic.bussiness.union.cross.CrossHuaBenBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.union.cross.UnionHuaBenProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.config.GoodsMgr;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.player.WorldMessageMgr;
import com.yanqu.road.server.manager.union.CrossUnionMgr;
import com.yanqu.road.server.manager.union.CrossUnionNoticeMgr;
import com.yanqu.road.server.manager.union.CrossUnionReqContext;
import com.yanqu.road.server.manager.union.trade.CrossUnionTradeMgr;
import com.yanqu.road.server.manger.TempGoodsBagMgr;
import com.yanqu.road.server.manger.UnionHuaBenServerGroupMgr;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.yanqu.road.server.manager.union.trade.CrossUnionTradeMgr.hasUnionTradeHiddenRoute;

public class CrossUnionHuaBenMgr extends TempMgr {

    /**
     * key:周id/区服id/商会uid
     * 商会每周话本
     */
    static Map<Integer, Map<Long, Map<String, UnionHuaBenPassWeekData>>> unionWeekDataMap;

    /**
     * key:周id/区服id/玩家
     * 成员每周话本
     */
    static Map<Integer, Map<Long, Map<Long, UnionHuaBenMemberWeekData>>> memberWeekDataMap;

    /**
     * key:区服id/商会uid
     * 商会话本（总体数据）
     */
    static Map<Long, Map<String, UnionHuaBenUnionData>> unionDataMap;

    /**
     * key:周id/区服id/商会id/关卡
     * 话本关卡攻击记录
     */
    static Map<Integer, Map<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>>> levelAttackWeekDataMap;

    /**
     * key:周id/分组id
     */
    static Map<Integer, Map<Integer, List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp>>> guanPuRecordMap = new ConcurrentHashMap<>();

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        int thisWeedId = CrossUnionHuaBenConfigMgr.getThisWeekId();
        int preWeedId = CrossUnionHuaBenConfigMgr.getPreWeekId();

        Map<Integer, Map<Long, Map<String, UnionHuaBenPassWeekData>>> unionWeekDataMapTemp = CrossHuaBenBussiness.getUnionHuaBenPassWeekDataMap(thisWeedId, preWeedId);
        Map<Integer, Map<Long, Map<Long, UnionHuaBenMemberWeekData>>> memberWeekDataMapTemp = CrossHuaBenBussiness.getUnionHuaBenMemberWeekDataMap(thisWeedId, preWeedId);
        Map<Integer, Map<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>>> levelAttackWeekDataMapTemp = CrossHuaBenBussiness.getUnionHuaBenAttackDamageDataMap(thisWeedId, preWeedId);
        Map<Long, Map<String, UnionHuaBenUnionData>> unionDataMapTemp = CrossHuaBenBussiness.getUnionHuaBenUnionDataMap();

        unionWeekDataMap = unionWeekDataMapTemp;
        unionDataMap = unionDataMapTemp;
        memberWeekDataMap = memberWeekDataMapTemp;
        levelAttackWeekDataMap = levelAttackWeekDataMapTemp;

        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public boolean save() {

        for (Map.Entry<Integer, Map<Long, Map<String, UnionHuaBenPassWeekData>>> entry : unionWeekDataMap.entrySet()) {
            for (Map.Entry<Long, Map<String, UnionHuaBenPassWeekData>> weekEntry : entry.getValue().entrySet()) {
                for (Map.Entry<String, UnionHuaBenPassWeekData> unionEntry : weekEntry.getValue().entrySet()) {
                    if(unionEntry.getValue().isInsertOption()){
                        CrossHuaBenBussiness.addUnionHuaBenPassWeekData(unionEntry.getValue());
                    }else if(unionEntry.getValue().isUpdateOption()){
                        CrossHuaBenBussiness.updateUnionHuaBenPassWeekData(unionEntry.getValue());
                    }
                }
            }
        }


        for (Map.Entry<Integer, Map<Long, Map<Long, UnionHuaBenMemberWeekData>>> entry : memberWeekDataMap.entrySet()) {
            for (Map.Entry<Long, Map<Long, UnionHuaBenMemberWeekData>> mapEntry : entry.getValue().entrySet()) {
                for (Map.Entry<Long, UnionHuaBenMemberWeekData> dataEntry : mapEntry.getValue().entrySet()) {
                    if(dataEntry.getValue().isInsertOption()){
                        CrossHuaBenBussiness.addUnionHuaBenMemberWeekData(dataEntry.getValue());
                    }else if(dataEntry.getValue().isUpdateOption()){
                        CrossHuaBenBussiness.updateUnionHuaBenMemberWeekData(dataEntry.getValue());
                    }
                }
            }
        }

        for (Map.Entry<Long, Map<String, UnionHuaBenUnionData>> entry : unionDataMap.entrySet()) {
            for (Map.Entry<String, UnionHuaBenUnionData> dataEntry : entry.getValue().entrySet()) {
                if(dataEntry.getValue().isInsertOption()){
                    CrossHuaBenBussiness.addUnionHuaBenUnionData(dataEntry.getValue());
                }else if(dataEntry.getValue().isUpdateOption()){
                    CrossHuaBenBussiness.updateUnionHuaBenUnionData(dataEntry.getValue());
                }
            }
        }

        for (Map.Entry<Integer, Map<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>>> entry : levelAttackWeekDataMap.entrySet()) {
            for (Map.Entry<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>> mapEntry : entry.getValue().entrySet()) {
                for (Map.Entry<String, Map<Integer, UnionHuaBenAttackDamageData>> unionEntry : mapEntry.getValue().entrySet()) {
                    for (Map.Entry<Integer, UnionHuaBenAttackDamageData> dataEntry : unionEntry.getValue().entrySet()) {
                        if(dataEntry.getValue().isInsertOption()){
                            CrossHuaBenBussiness.addUnionHuaBenAttackDamageData(dataEntry.getValue());
                        }else if(dataEntry.getValue().isUpdateOption()){
                            CrossHuaBenBussiness.updateUnionHuaBenAttackDamageData(dataEntry.getValue());
                        }
                    }
                }
            }
        }

        return true;
    }

    /**
     * 添加每周商会话本数据
     * @param weekId 周id
     * @param serverId 商会区服
     * @param weekData 周话本数据
     */
    public static void addUnionHuaBenPassWeekData(int weekId, long serverId, UnionHuaBenPassWeekData weekData){

        Map<Long, Map<String, UnionHuaBenPassWeekData>> weekDataMap = unionWeekDataMap.get(weekId);
        if(weekDataMap == null){
            synchronized (unionWeekDataMap){
                weekDataMap = unionWeekDataMap.get(weekId);
                if(weekDataMap == null){
                    unionWeekDataMap.put(weekId, new ConcurrentHashMap<>());
                    weekDataMap = unionWeekDataMap.get(weekId);
                }
            }
        }

        Map<String, UnionHuaBenPassWeekData> serverDataMap = weekDataMap.get(serverId);
        if(serverDataMap == null){
            synchronized (weekDataMap){
                serverDataMap = weekDataMap.get(serverId);
                if(serverDataMap == null){
                    weekDataMap.put(serverId, new ConcurrentHashMap<>());
                    serverDataMap = weekDataMap.get(serverId);
                }
            }
        }

        synchronized (serverDataMap) {
            if (!serverDataMap.containsKey(weekData.getUnionUid())) {
                serverDataMap.put(weekData.getUnionUid(), weekData);
            }
        }

    }

    /**
     * 添加成员每周话本参与数据
     * @param weekId 周id
     * @param serverId 成员区服
     * @param memberWeekData 成员周数据
     */
    public static void addUnionHuaBenMemberWeekData(int weekId, long serverId, UnionHuaBenMemberWeekData memberWeekData){

        Map<Long, Map<Long, UnionHuaBenMemberWeekData>> weekDataMap = memberWeekDataMap.get(weekId);
        if(weekDataMap == null){
            synchronized (memberWeekDataMap){
                weekDataMap = memberWeekDataMap.get(weekId);
                if(weekDataMap == null){
                    weekDataMap = new ConcurrentHashMap<>();
                    memberWeekDataMap.put(weekId, weekDataMap);
                }
            }
        }

        Map<Long, UnionHuaBenMemberWeekData> serverDataMap = weekDataMap.get(serverId);
        if(serverDataMap == null){
            synchronized (weekDataMap){
                serverDataMap = weekDataMap.get(serverId);
                if(serverDataMap == null){
                    serverDataMap = new ConcurrentHashMap<>();
                    weekDataMap.put(serverId, serverDataMap);
                }
            }
        }

        synchronized (serverDataMap){
            if(!serverDataMap.containsKey(memberWeekData.getUserId())){
                serverDataMap.put(memberWeekData.getUserId(), memberWeekData);
            }
        }

    }

    /**
     * 添加每周话本伤害记录
     * @param weekId 周id
     * @param serverId 商会区服
     * @param unionUid 商会uid
     * @param damageData 伤害记录
     */
    public static void addUnionHuaBenAttackDamageData(int weekId, long serverId, String unionUid, UnionHuaBenAttackDamageData damageData){
        Map<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>> weekDataMap = levelAttackWeekDataMap.get(weekId);
        if(weekDataMap == null){
            synchronized (levelAttackWeekDataMap){
                weekDataMap = levelAttackWeekDataMap.get(weekId);
                if(weekDataMap == null){
                    weekDataMap = new ConcurrentHashMap<>();
                    levelAttackWeekDataMap.put(weekId, weekDataMap);
                }
            }
        }

        Map<String, Map<Integer, UnionHuaBenAttackDamageData>> serverDataMap = weekDataMap.get(serverId);
        if(serverDataMap == null){
            synchronized (weekDataMap){
                serverDataMap = weekDataMap.get(serverId);
                if(serverDataMap == null){
                    serverDataMap = new ConcurrentHashMap<>();
                    weekDataMap.put(serverId, serverDataMap);
                }
            }
        }

        Map<Integer, UnionHuaBenAttackDamageData> unionDataMap = serverDataMap.get(unionUid);
        if(unionDataMap == null){
            synchronized (serverDataMap){
                unionDataMap = serverDataMap.get(unionUid);
                if(unionDataMap == null){
                    unionDataMap = new ConcurrentHashMap<>();
                    serverDataMap.put(unionUid, unionDataMap);
                }
            }
        }

        synchronized (unionDataMap){
            if(!unionDataMap.containsKey(damageData.getLevel())){
                unionDataMap.put(damageData.getLevel(), damageData);
            }
        }

    }

    public static void addUnionHuaBenUnionData(long serverId, String unionUid, UnionHuaBenUnionData unionData){
        Map<String, UnionHuaBenUnionData> map = unionDataMap.get(serverId);
        if(map == null){
            synchronized (unionDataMap){
                map = unionDataMap.get(serverId);
                if(map == null){
                    map = new ConcurrentHashMap<>();
                    unionDataMap.put(serverId, map);
                }
            }
        }
        synchronized (map){
            map.put(unionUid, unionData);
        }
    }

    public static UnionHuaBenPassWeekData getUnionHuaBenPassWeekData(int weekId, long serverId, String unionUid){

        Map<Long, Map<String, UnionHuaBenPassWeekData>> weekDataMap = unionWeekDataMap.get(weekId);
        if(weekDataMap == null){
            return null;
        }

        Map<String, UnionHuaBenPassWeekData> serverDataMap = weekDataMap.get(serverId);
        if(serverDataMap == null){
            return null;
        }

        return serverDataMap.get(unionUid);
    }

    public static UnionHuaBenMemberWeekData getUnionHuaBenMemberWeekData(int weekId, long serverId, long userId){
        Map<Long, Map<Long, UnionHuaBenMemberWeekData>> weekDataMap = memberWeekDataMap.get(weekId);
        if(weekDataMap == null){
            return null;
        }
        Map<Long, UnionHuaBenMemberWeekData> serverDataMap = weekDataMap.get(serverId);
        if(serverDataMap == null){
            return null;
        }
        return serverDataMap.get(userId);
    }

    public static UnionHuaBenUnionData getUnionHuaBenUnionData(long serverId, String unionUid){
        Map<String, UnionHuaBenUnionData> map = unionDataMap.get(serverId);
        if(map == null){
            return null;
        }
        return map.get(unionUid);
    }

    public static UnionHuaBenAttackDamageData getUnionHuaBenAttackDamageData(int weekId, long serverId, String unionUid, int level){
        Map<Long, Map<String, Map<Integer, UnionHuaBenAttackDamageData>>> attackWeekDataMap = levelAttackWeekDataMap.get(weekId);
        if(attackWeekDataMap == null){
            return null;
        }

        Map<String, Map<Integer, UnionHuaBenAttackDamageData>> serverDataMap = attackWeekDataMap.get(serverId);
        if(serverDataMap == null){
            return null;
        }

        Map<Integer, UnionHuaBenAttackDamageData> unionDataMap = serverDataMap.get(unionUid);
        if(unionDataMap == null){
            return null;
        }

        return unionDataMap.get(level);
    }

    public static void userLogin(long serverId, long playerId) {

        CrossUnionReqContext context = CrossUnionReqContext.initContext(serverId, playerId).loadUnionMember().loadUnionInfo();
        if(context.getRet() != 0){
            return;
        }
        CrossUnionHuaBenConfigMgr.syncConfig(context.getUnionInfo(), context.getMember());

        syncHuaBenData(context.getUnionInfo(), context.getMember(), null);

        syncMemberData(context.getMember().getServerId(), playerId);

        checkSettleReward(serverId, playerId);

    }

    /**
     * 检测是否有话本计算积分未发放
     */
    private static void checkSettleReward(long serverId, long playerId) {
        //检测是否有结算发奖未下发
        List<Integer> weekList = new ArrayList<>();
        int thisWeekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
        int preWeekId = CrossUnionHuaBenConfigMgr.getPreWeekId();
        weekList.add(thisWeekId);
        weekList.add(preWeekId);
        for (int weekId : weekList) {
            UnionHuaBenMemberWeekData weekData = getUnionHuaBenMemberWeekData(weekId, serverId, playerId);
            if(weekData != null){
                synchronized (weekData){
                    if(!weekData.isSettleSync() && weekData.getSettleScore() > 0){
                        UnionHuaBenPassWeekData passWeekData = getUnionHuaBenPassWeekData(weekId, weekData.getServerId(), weekData.getUnionUid());
                        //检测所在话本已结算超过一个小时
                        if(passWeekData != null && passWeekData.getCloseTime() > 0 && passWeekData.getCloseTime() + DateHelper.HOUR_SECONDS <= DateHelper.getCurrentSecond()){
                            //评价
                            List<String> pingJiaTextList = StringUtils.stringToStringList(GameConfig.UNION_STORY_EVALUE_LV, "\\|");
                            UnionHuaBenProto.UnionHuaBenSettleMailScoreSyncMsg.Builder syncMsg = UnionHuaBenProto.UnionHuaBenSettleMailScoreSyncMsg.newBuilder();
                            syncMsg.setPingJia(pingJiaTextList.get(passWeekData.getPingJia() - 1));
                            syncMsg.setWeekId(weekData.getWeekId());
                            UnionHuaBenProto.UnionHuaBenSettleMailScoreTemp.Builder userBuild = UnionHuaBenProto.UnionHuaBenSettleMailScoreTemp.newBuilder();
                            userBuild.setScore(weekData.getSettleScore());
                            userBuild.setUserId(weekData.getUserId());
                            syncMsg.addUserScore(userBuild);
                            MessageHelper.sendPacket(weekData.getServerId(), 0, YanQuMessageUtils.buildMessage(Protocol.S_CROSS_UNION_HUA_BEN_SETTLE_REWARD_TO_MEMBER, syncMsg));
                            weekData.setSettleSync(true);
                        }
                    }
                }
            }
        }
    }

    public static void syncMemberData(long serverId, long playerId) {
        int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
        UnionHuaBenMemberWeekData memberWeekData = getUnionHuaBenMemberWeekData(weekId, serverId, playerId);
        UnionHuaBenProto.UnionHuaBenServerUserDataSyncMsg.Builder syncBuilder = UnionHuaBenProto.UnionHuaBenServerUserDataSyncMsg.newBuilder();
        if(memberWeekData != null) {
            resetMemberWeekData(memberWeekData);
            syncBuilder.setCanSendTimes(memberWeekData.getCanSendTimes());
            syncBuilder.setResetTime(memberWeekData.getResetTime());
            syncBuilder.setUnionUid(memberWeekData.getUnionUid());
        }
        MessageHelper.sendPacket(serverId, playerId, YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_USER_DATA_SYNC, syncBuilder));
    }

    /**
     * 开启话本
     */
    public static int openHuaBen(long serverId, long playerId, int degree){

        //会长权限
        CrossUnionReqContext context = CrossUnionReqContext.initContext(serverId, playerId).loadUnionMember().loadUnionInfo();
        if(context.getRet() != 0){
            return context.getRet();
        }

        if(context.getMember().getPosition() != eUnionPosition.Master.getValue() && context.getMember().getPosition() != eUnionPosition.DeputyMaster.getValue()){
            return GameErrorCode.E_UNION_POSITION_NO_ENOUGH;
        }

        if(!context.getUnionInfo().isCross()){
            return GameErrorCode.E_UNION_IS_NOT_CROSS_UNION;
        }

        int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();

        synchronized (context.getUnionInfo()) {
            //时间限制，周日22点后
            if (CrossUnionHuaBenRankMgr.isSunDayLast4Hour()) {
                return GameErrorCode.E_CROSS_UNION_HUA_BEN_HAD_SETTLE;
            }

            //所在分组的话本基础配置
            Map<Integer, Map<Integer, UnionHuaBenBaseTempData>> baseTempDataMap = CrossUnionHuaBenConfigMgr.getWeekServerTempData(weekId, serverId);
            if (baseTempDataMap == null) {
                return GameErrorCode.E_CROSS_UNION_HUA_BEN_CONFIG_NO_FOUND;
            }

            Map<Integer, UnionHuaBenBaseTempData> degreeBaseTempDataMap = baseTempDataMap.get(degree);
            if (degreeBaseTempDataMap == null) {
                return GameErrorCode.E_CROSS_UNION_HUA_BEN_CONFIG_NO_FOUND;
            }

            UnionHuaBenUnionData unionData = getUnionHuaBenUnionData(context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid());
            if (unionData == null) {
                unionData = new UnionHuaBenUnionData();
                unionData.setInsertOption();
                unionData.setUnionUid(context.getUnionInfo().getUnionUid());
                unionData.setServerId(context.getUnionInfo().getServerId());
                addUnionHuaBenUnionData(context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid(), unionData);
            }

            //难度不是简单，判定开启条件
            if (degree > 1 && !reachOpenLimit(unionData, degree)) {
                return GameErrorCode.E_CROSS_UNION_HUA_BEN_OPEN_LIMITED;
            }

            UnionHuaBenPassWeekData weekData = getUnionHuaBenPassWeekData(weekId, context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid());
            if (weekData == null) {
                weekData = new UnionHuaBenPassWeekData();
                weekData.setWeekId(weekId);
                weekData.setUnionUid(context.getUnionInfo().getUnionUid());
                weekData.setServerId(context.getUnionInfo().getServerId());
                weekData.setDegree(degree);
                weekData.setInsertOption();
            } else {
                if (weekData.getOpenTime() > 0) {
                    return GameErrorCode.E_CROSS_UNION_HUA_BEN_HAD_OPEN;
                }
            }

            //根据基础配置生成话本 关卡数据
            int levelNum = degreeBaseTempDataMap.size();
            for (int i = 0; i < levelNum; i++) {
                UnionHuaBenBaseTempData tempData = degreeBaseTempDataMap.get(i + 1);
                UnionHuaBenPass pass = new UnionHuaBenPass();
                pass.setBlood(tempData.getBossHP());
                //固定5个小怪
                for (int i1 = 0; i1 < 5; i1++) {
                    //小怪
                    UnionHuaBenPassMonster monster = new UnionHuaBenPassMonster();
                    monster.setWave(1);
                    monster.setBlood(tempData.getMonsterHP());
                    //职业
                    monster.setOccupat(i1 + 1);
                    pass.getMonsterList().add(monster);
                }
                weekData.getPassList().add(pass);
            }
            weekData.setDuration(CrossUnionHuaBenConfigMgr.getStroyMissionExistTime(degree));
            weekData.setOpenTime(DateHelper.getCurrentSecond());

            List<UnionHuaBenMemberWeekData> memberWeekDataList = new ArrayList<>();
            //锁定成员
            Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(context.getUnionInfo().getUnionUid());
            if (memberMap != null) {
                for (Map.Entry<Long, CrossUnionMember> entry : memberMap.entrySet()) {
                    UnionHuaBenMemberWeekData oldMemberWeekData = getUnionHuaBenMemberWeekData(weekId, entry.getValue().getServerId(), entry.getValue().getUserId());
                    if(oldMemberWeekData != null){
                        memberWeekDataList.add(oldMemberWeekData);
                        continue;
                    }
                    UnionHuaBenMemberWeekData memberWeekData = new UnionHuaBenMemberWeekData();
                    memberWeekData.setInsertOption();
                    CrossUnionMember member = entry.getValue();
                    memberWeekData.setUserId(member.getUserId());
                    memberWeekData.setServerId(member.getServerId());
                    memberWeekData.setUnionUid(context.getUnionInfo().getUnionUid());
                    memberWeekData.setCanSendTimes(GameConfig.UNION_STORY_FIGHT_ADD_NUM_PLAYER);
                    memberWeekData.setResetTime(DateHelper.getCurrentSecond());
                    memberWeekData.setWeekId(weekId);
                    addUnionHuaBenMemberWeekData(weekId, member.getServerId(), memberWeekData);
                    memberWeekDataList.add(memberWeekData);
                }
            }

            if (weekData.isInsertOption()) {
                addUnionHuaBenPassWeekData(weekId, context.getUnionInfo().getServerId(), weekData);
            }

            syncHuaBenData(context.getUnionInfo(), weekData);

            syncMemberData(memberWeekDataList);

            MessageHelper.sendPacket(serverId, playerId, YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_OPEN, UnionHuaBenProto.UnionHuaBenOpenRespMsg.newBuilder().setRet(0)));

            //日志
            CrossAutoLogMgr.add(new LogUnionHuaBenOpen(context.getUnionInfo().getUnionUid(), weekId, context.getUnionInfo().getServerId(), context.getUnionInfo().getMasterUserId(), degree,
                    context.getUnionInfo().getMemberCount(), context.getUnionInfo().getTotalEarnSpeed().toString()));

            //公告
            CrossUnionNoticeMgr.addNotice(context.getUserBaseInfo(), context.getUnionInfo().getUnionUid(), eUnionNoticeType.HuaBen.getValue(), context.getMember().getUserBaseInfo().getNickName(), context.getMember().getServerId());
        }
        return 0;
    }

    private static void syncMemberData(List<UnionHuaBenMemberWeekData> memberWeekDataList) {
        for (UnionHuaBenMemberWeekData memberWeekData : memberWeekDataList) {
            UnionHuaBenProto.UnionHuaBenServerUserDataSyncMsg.Builder syncBuilder = UnionHuaBenProto.UnionHuaBenServerUserDataSyncMsg.newBuilder();
            syncBuilder.setCanSendTimes(memberWeekData.getCanSendTimes());
            syncBuilder.setResetTime(memberWeekData.getResetTime());
            syncBuilder.setUnionUid(memberWeekData.getUnionUid());
            MessageHelper.sendPacket(memberWeekData.getServerId(), memberWeekData.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_USER_DATA_SYNC, syncBuilder));
        }
    }

    private static boolean reachOpenLimit(UnionHuaBenUnionData unionData, int degree) {
        List<Integer> sortList = StringUtils.stringToIntegerList(GameConfig.UNION_STORY_SORT, ",");
        int degreeIndex = sortList.indexOf(degree);
        int preDegree = sortList.get(degreeIndex - 1);
//        int preDegree = degree - 1;
        int pingJis = GameConfig.UNION_STORY_OPEN_LIMIT;
        List<Integer> timesList = StringUtils.stringToIntegerList(GameConfig.UNION_STORY_OPEN_LIMIT_GETNUM, "\\|");
        int times = timesList.get(degree - 1);
        Map<Integer, Integer> pingJiaMap = unionData.getGradeMap().get(preDegree);
        if(pingJiaMap != null){
            int allNum = 0;
            for (Map.Entry<Integer, Integer> entry : pingJiaMap.entrySet()) {
                int pj = entry.getKey();
                int num = entry.getValue();
                if(pj >= pingJis){
                    allNum += num;
                }
            }
            if(allNum >= times){
                return true;
            }
        }
        //已开启过，有评价的，可以继续
        if(unionData.getGradeMap().containsKey(degree)){
            return true;
        }
        return false;
    }

    /**
     * 派遣门客战斗
     */
    public static UnionHuaBenProto.UnionHuaBenDispatchCrossRespMsg.Builder dispatchFight(long serverId, long playerId, int idx, List<UnionHuaBenPatrons> patronsList, int level) {

        UnionHuaBenProto.UnionHuaBenDispatchCrossRespMsg.Builder respMsg = UnionHuaBenProto.UnionHuaBenDispatchCrossRespMsg.newBuilder();
        respMsg.setIdx(idx);
        respMsg.setRouteId(0);
        respMsg.setHuaBenEnd(false);
        CrossUnionReqContext context = CrossUnionReqContext.initContext(serverId, playerId).loadUnionMember().loadUnionInfo();
        if(context.getRet() != 0){
            respMsg.setRet(context.getRet());
            return respMsg;
        }

        if(!context.getUnionInfo().isCross()){
            respMsg.setRet(GameErrorCode.E_UNION_IS_NOT_CROSS_UNION);
            return respMsg;
        }

        int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();

        UnionHuaBenMemberWeekData memberWeekData = getUnionHuaBenMemberWeekData(weekId, context.getMember().getServerId(), context.getPlayerId());
        if(memberWeekData == null || !Objects.equals(memberWeekData.getUnionUid(), context.getUnionInfo().getUnionUid())){
            respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_NO_QUALIFIED);
            return respMsg;
        }

        resetMemberWeekData(memberWeekData);
        if(memberWeekData.getCanSendTimes() <= 0){
            respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_NO_SEND_TIME);
            return respMsg;
        }

        UnionHuaBenUnionData unionData = getUnionHuaBenUnionData(context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid());
        UnionHuaBenPassWeekData weekData = getUnionHuaBenPassWeekData(weekId, context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid());
        if(unionData == null || weekData == null){
            respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_DATA_NOT_FOUND);
            return respMsg;
        }

        UnionHuaBenBaseTempData benBaseTempData = CrossUnionHuaBenConfigMgr.getWeekServerTempData(weekId, context.getUnionInfo().getServerId(), weekData.getDegree(), level);
        if(benBaseTempData == null){
            respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_CONFIG_NOT_FOUND);
            return respMsg;
        }

        synchronized (weekData) {
            //时间限制，周日22点后
            if (CrossUnionHuaBenRankMgr.isSunDayLast4Hour()) {
                respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_HAD_SETTLE);
                return respMsg;
            }
            //时间限制，话本有效期
            if (weekData.getOpenTime() + weekData.getDuration() * DateHelper.MINUTE_SECONDS < DateHelper.getCurrentSecond()) {
                respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_HAD_SETTLE);
                settleWeekData(weekData);
                return respMsg;
            }

            if (weekData.getCloseTime() > 0) {
                respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_HAD_SETTLE);
                return respMsg;
            }

            if (level > weekData.getPassList().size()) {
                respMsg.setRet(GameErrorCode.E_REQUEST_ARGUMENT_ERROR);
                return respMsg;
            }
            UnionHuaBenPass pass = weekData.getPassList().get(level - 1);
            if (pass.isEnd()) {
                respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_LEVEL_HAD_END);
                return respMsg;
            }
            if (level > 1) {
                UnionHuaBenPass prePass = weekData.getPassList().get(level - 2);
                if (!prePass.isEnd()) {
                    respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_PRE_PASS_NOT_END);
                    return respMsg;
                }
            }
            //日志
            int wave = 0;
            int targetId;
            String beforeBlood;
            String afterBlood;
            //击败奖励
            Property dieProperty = new Property();
            Property boxProperty = new Property();
            int boxId = 0;
            //关卡是否结束
            boolean passEnd = false;
            BigInteger damage;
            int score;
            if (idx == 0) {
                targetId = benBaseTempData.getBossIcon();
                //攻击boss
                boolean canAttackBoss = canAttackBoss(pass.getMonsterList(), benBaseTempData.getMonsterWave());
                if (!canAttackBoss) {
                    respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_UNABLE_ATTACK);
                    return respMsg;
                }
                beforeBlood = pass.getBlood();
                BigInteger bossBlood = new BigInteger(pass.getBlood());
                damage = calAttackBlood(idx, patronsList, bossBlood);
                bossBlood = bossBlood.subtract(damage);
                if (bossBlood.compareTo(BigInteger.ZERO) == 0) {
                    passEnd = true;
                    boxId = benBaseTempData.getBossReward();
                    dieProperty.addProperty(PropertyHelper.parseStringToProperty(benBaseTempData.getBossSReward()));

                    //击杀消息
                    WorldMessageProto.WorldMessageTempMsg.Builder killMsg = WorldMessageMgr.parseWorldMessageTempMsg(context.getUserBaseInfo().getUserBaseInfo(), context.getPlayerId(),
                            eMessageType.UnionHuaBenKillBoss.getValue(), eChatContentType.Common.getContentType(), benBaseTempData.getBossIcon() + "", System.currentTimeMillis(), 0, null);
                    WorldMessageMgr.sendUnionChat(context.getMember().getServerId(), context.getMember().getUserId(), killMsg, context.getUnionInfo().getUnionUid());
                }
                pass.setBlood(bossBlood.toString());
                afterBlood = pass.getBlood();
                //伤害榜
                addAttackRecord(playerId, level, context, weekId, benBaseTempData.getBossIcon(), damage, 1, bossBlood.compareTo(BigInteger.ZERO) == 0);
                score = calDamageScore(damage, benBaseTempData.getBossHP(), benBaseTempData.getBossScore());
            } else {
                targetId = benBaseTempData.getMonsterIcon().get(idx - 1);
                UnionHuaBenPassMonster monster = pass.getMonsterList().get(idx - 1);
                wave = monster.getWave();
                if (isMonsterDie(benBaseTempData.getMonsterWave(), monster)) {
                    respMsg.setRet(GameErrorCode.E_CROSS_UNION_HUA_BEN_MONSTER_HAD_DIE);
                    return respMsg;
                }
                beforeBlood = monster.getBlood();
                BigInteger blood = new BigInteger(monster.getBlood());
                damage = calAttackBlood(idx, patronsList, blood);
                blood = blood.subtract(damage);
                monster.setBlood(blood.toString());
                afterBlood = monster.getBlood();
                if (blood.compareTo(BigInteger.ZERO) == 0) {
                    boxId = benBaseTempData.getMonsterReward();
                }
                if (blood.compareTo(BigInteger.ZERO) == 0 && monster.getWave() < benBaseTempData.getMonsterWave()) {
                    monster.setWave(1 + monster.getWave());
                    monster.setBlood(benBaseTempData.getMonsterHP());
                }
                //伤害榜
                addAttackRecord(playerId, level, context, weekId, benBaseTempData.getMonsterIcon().get(idx - 1), damage, wave, blood.compareTo(BigInteger.ZERO) == 0);
                BigInteger totalHp = new BigInteger(benBaseTempData.getMonsterHP());
                totalHp = totalHp.multiply(BigInteger.valueOf(5 * benBaseTempData.getMonsterWave()));
                score = calDamageScore(damage, totalHp.toString(), benBaseTempData.getMonsterScore());
            }

            synchronized (memberWeekData) {
                memberWeekData.setCanSendTimes(memberWeekData.getCanSendTimes() - 1);
                memberWeekData.setSendTimes(memberWeekData.getSendTimes() + 1);
                memberWeekData.setScore(memberWeekData.getScore() + score);
            }
            String reward = PropertyHelper.parseGoodsToString(GameConfig.UNION_STORY_SCORE_ID, BigInteger.valueOf(score));
            Property allReward = new Property();
            allReward.addProperty(dieProperty);
            allReward.addProperty(PropertyHelper.parseStringToProperty(reward));
            if(boxId > 0){
                if(GoodsMgr.getGoodsInfo(boxId) != null){
                    OpenGoodsBagResult openResult = TempGoodsBagMgr.getRandomGoods(boxId);
                    boxProperty = openResult.getReward();
                }
            }
            respMsg.setRet(0);
            for (UnionHuaBenPatrons patrons : patronsList) {
                respMsg.addPatronsId(patrons.getPatronsId());
                respMsg.addDamage(patrons.getDamage());
            }

            respMsg.setPass(passEnd);
            pass.setEnd(passEnd);
            if (passEnd) {
                //话本是否结束
                boolean huaBenEnd = true;
                for (UnionHuaBenPass benPass : weekData.getPassList()) {
                    if (!benPass.isEnd()) {
                        huaBenEnd = false;
                        break;
                    }
                }
                respMsg.setHuaBenEnd(huaBenEnd);
                weekData.setLastPassTime(DateHelper.getCurrentSecond());
                int routeId = triggerRouteUnLock(context.getUnionInfo(), benBaseTempData, context.getMember());
                respMsg.setRouteId(routeId);
                if (huaBenEnd) {
                    //结算
                    weekData.setCloseTime(DateHelper.getCurrentSecond());
                    //话本评级
                    int addition = calPingjia(weekData, unionData);

                    //话本结束，发送邮件奖励（主要是积分）
                    sendHuaBenEndMemberReward(context.getUnionInfo(), weekData, addition);

                } else {
                    calPingjia(weekData, unionData);
                }

                //榜单
                CrossUnionWeekRank weekRank = initCrossUnionWeekRank(weekData, context.getUnionInfo());
                CrossUnionHuaBenRankMgr.changeUnionRank(weekData.getWeekId(), context.getUnionInfo().getServerId(), weekRank);

                //过关提醒
                //商会频道消息
                String content = WorldMessageMgr.encodeContent(context.getUserBaseInfo().getUserBaseInfo().getNickName(), context.getMember().getServerId(), level, benBaseTempData.getBossIcon());
                WorldMessageProto.WorldMessageTempMsg.Builder chatMsg = WorldMessageMgr.parseWorldMessageTempMsg(context.getUserBaseInfo(),
                        eMessageType.UnionHuaBenPassForUnion.getValue(), eChatContentType.Common.getContentType(), content, DateHelper.getCurrentTime(), 0, null);
                WorldMessageMgr.sendUnionChat(context.getMember().getServerId(), context.getPlayerId(), chatMsg, context.getUnionInfo().getUnionUid());
                //话本频道
                WorldMessageProto.WorldMessageTempMsg.Builder chatMsg2 = WorldMessageMgr.parseWorldMessageTempMsg(context.getUserBaseInfo(),
                        eMessageType.UnionHuaBenPass.getValue(), eChatContentType.Common.getContentType(), content, DateHelper.getCurrentTime(), 0, null);
                WorldMessageMgr.sendSystemGroupChat(context.getMember().getServerId(), context.getPlayerId(), chatMsg2, eSystemId.CrossHuaBen.getValue());
            }
            weekData.setUpdateOption();
            syncHuaBenData(context.getUnionInfo(), weekData);
            syncMemberData(context.getMember().getServerId(), context.getPlayerId());

            if (passEnd) {
                //通关日志
                CrossAutoLogMgr.add(new LogUnionHuaBenLevelPass(context.getUnionInfo().getUnionUid(), weekId, context.getPlayerId(), weekData.getDegree(), level, respMsg.getRouteId()));
                //评价日志
                CrossAutoLogMgr.add(new LogUnionHuaBenPingJia(context.getUnionInfo().getUnionUid(), weekId, context.getPlayerId(), weekData.getDegree(), weekData.getOpenTime(), weekData.getLastPassTime(), weekData.getPingJia()));
            }

            //伤害日志
            CrossAutoLogMgr.add(new LogUnionHuaBenAttack(context.getUnionInfo().getUnionUid(), weekId, context.getPlayerId(), weekData.getDegree(), level, wave, targetId,
                    patronsList, damage.toString(), beforeBlood, afterBlood, PropertyHelper.parsePropertyToString(allReward), PropertyHelper.parsePropertyToString(boxProperty)));

            allReward.addProperty(boxProperty);
            respMsg.setReward(PropertyHelper.parsePropertyToString(allReward));
            return respMsg;
        }
    }

    /**
     * 计算伤害积分
     */
    private static int calDamageScore(BigInteger damage, String monsterHP, int monsterScore) {
        return new BigDecimal(damage.toString()).multiply(BigDecimal.valueOf(monsterScore)).divide(new BigDecimal(monsterHP), 0, BigDecimal.ROUND_UP).intValue();
    }

    private static void resetMemberWeekData(UnionHuaBenMemberWeekData memberWeekData) {
        int now = DateHelper.getCurrentSecond();
        synchronized (memberWeekData) {
            long gapNum = (now - memberWeekData.getResetTime()) / (DateHelper.HOUR_SECONDS * GameConfig.UNION_STORY_FIGHT_ADD_CD_PLAYER);
            if (gapNum > 0) {
                memberWeekData.setCanSendTimes(memberWeekData.getCanSendTimes() + GameConfig.UNION_STORY_FIGHT_ADD_NUM_PLAYER * (int) gapNum);
                memberWeekData.setResetTime(memberWeekData.getResetTime() + (int) (gapNum * DateHelper.HOUR_SECONDS * GameConfig.UNION_STORY_FIGHT_ADD_CD_PLAYER));
            }
        }
    }

    private static CrossUnionWeekRank initCrossUnionWeekRank(UnionHuaBenPassWeekData weekData, CrossUnionInfo unionInfo) {
        CrossUnionWeekRank weekRank = new CrossUnionWeekRank();
        weekRank.setServerId(unionInfo.getServerId());
        weekRank.setWeekId(weekData.getWeekId());
        weekRank.setUnionUid(unionInfo.getUnionUid());
        weekRank.setValue(BigInteger.valueOf(getPassNum(weekData.getPassList())));
        weekRank.setType(weekData.getDegree());
        weekRank.setLastUpdateTime(DateHelper.getCurrentTime());
        weekRank.setUnionBaseInfo(CrossUnionMgr.parseUnionBaseInfo(unionInfo));
        weekRank.setParam("" + calHuaBenPassTime(DateHelper.getCurrentSecond(), weekData));
        return weekRank;
    }

    private static void sendHuaBenEndMemberReward(CrossUnionInfo unionInfo, UnionHuaBenPassWeekData weekData, int addition) {
        if(addition > 0) {
            //成员积分  额外邮件发送
            List<UnionHuaBenMemberWeekData> memberWeekDataList = new ArrayList<>();
            Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(unionInfo.getUnionUid());
            if (memberMap != null) {
                for (Map.Entry<Long, CrossUnionMember> memberEntry : memberMap.entrySet()) {
                    CrossUnionMember member = memberEntry.getValue();
                    UnionHuaBenMemberWeekData benMemberWeekData = getUnionHuaBenMemberWeekData(weekData.getWeekId(), member.getServerId(), member.getUserId());
                    if (benMemberWeekData != null) {
                        memberWeekDataList.add(benMemberWeekData);
                    }
                }
            }
            //serverId  userId
            Map<Long, Map<Long, Integer>> addScoreMap = new HashMap<>();
            for (UnionHuaBenMemberWeekData benMemberWeekData : memberWeekDataList) {
                CrossUnionMember member = CrossUnionMgr.getUnionMember(unionInfo.getUnionUid(), benMemberWeekData.getUserId());
                if(member != null) {
                    if (addScoreMap.get(member.getServerId()) == null){
                        addScoreMap.put(member.getServerId(), new HashMap<>());
                    }
                    //if(benMemberWeekData.getScore() > 0){
                        //int addScore = BigDecimal.valueOf(benMemberWeekData.getScore()).multiply(BigDecimal.valueOf(addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
                        addScoreMap.get(member.getServerId()).put(member.getUserId(), addition);
                        benMemberWeekData.setUserBaseInfo(member.getUserBaseInfo());
                        benMemberWeekData.setSettleScore(addition);
                    //}
                }
            }
            //评价
            List<String> pingJiaTextList = StringUtils.stringToStringList(GameConfig.UNION_STORY_EVALUE_LV, "\\|");
            for (Map.Entry<Long, Map<Long, Integer>> entry : addScoreMap.entrySet()) {
                UnionHuaBenProto.UnionHuaBenSettleMailScoreSyncMsg.Builder syncMsg = UnionHuaBenProto.UnionHuaBenSettleMailScoreSyncMsg.newBuilder();
                syncMsg.setPingJia(pingJiaTextList.get(weekData.getPingJia() - 1));
                syncMsg.setWeekId(weekData.getWeekId());
                for (Map.Entry<Long, Integer> innerEntry : entry.getValue().entrySet()) {
                    UnionHuaBenProto.UnionHuaBenSettleMailScoreTemp.Builder userBuild = UnionHuaBenProto.UnionHuaBenSettleMailScoreTemp.newBuilder();
                    userBuild.setScore(innerEntry.getValue());
                    userBuild.setUserId(innerEntry.getKey());
                    syncMsg.addUserScore(userBuild);
                }
                MessageHelper.sendPacket(entry.getKey(), 0, YanQuMessageUtils.buildMessage(Protocol.S_CROSS_UNION_HUA_BEN_SETTLE_REWARD_TO_MEMBER, syncMsg));
            }
        }
    }

    //触发 解锁隐藏的商贸路线
    private static int triggerRouteUnLock(CrossUnionInfo unionInfo, UnionHuaBenBaseTempData benBaseTempData, CrossUnionMember member) {
        int routeId = 0;
        //商贸路线触发
        Random random = new Random();
        List<Integer> routeRandomList = StringUtils.stringToIntegerList(benBaseTempData.getProbability(), ";");
        int num = CrossUnionTradeMgr.getUnionTradeHiddenRouteNum(unionInfo.getUnionUid());
        if(num < GameConfig.UNION_STORY_TRADE_EXIST_MAXNUM && !hasUnionTradeHiddenRoute(unionInfo.getUnionUid(), routeRandomList.get(0)) && random.nextInt(1000) < routeRandomList.get(1)){
            CrossUnionTradeMgr.addUnionTradeHiddenRouteUnLock(unionInfo.getUnionUid(), routeRandomList.get(0));
            routeId = routeRandomList.get(0);
        }
        if(routeId > 0){
            WorldMessageProto.WorldMessageTempMsg.Builder bussinessMsg = WorldMessageMgr.parseWorldMessageTempMsg(member.getUserBaseInfo(), member.getUserId(),
                    eMessageType.UnionHuaBenTradeRoute.getValue(), eChatContentType.Common.getContentType(), benBaseTempData.getBossIcon() + ";" + routeId, System.currentTimeMillis(), 0, null);
            WorldMessageMgr.sendUnionChat(member.getServerId(), member.getUserId(), bussinessMsg, unionInfo.getUnionUid());
        }
        return routeId;
    }

    /**
     * 计算话本评价
     */
    private static int calPingjia(UnionHuaBenPassWeekData weekData, UnionHuaBenUnionData unionData) {
        int passNum = getPassNum(weekData.getPassList());
        //改为秒
        int min;
        if(weekData.getLastPassTime() > 0){
            min = (weekData.getLastPassTime() - weekData.getOpenTime());
        }else {
            min = (weekData.getCloseTime() - weekData.getOpenTime());
        }
        int addition = 0;
        List<String> stringList = StringUtils.stringToStringList(GameConfig.UNION_STORY_GRADE_LIMIT, "\\|");
        for (int i = 0; i < stringList.size(); i++) {
            String str = stringList.get(i);
            List<Integer> valList = StringUtils.stringToIntegerList(str, ";");
            if(passNum >= valList.get(0) && (valList.get(1) == -1 || (valList.get(1) != -1 && min <= valList.get(1) * 60))){
                weekData.setPingJia(i + 1);
            }
        }
        if(weekData.getPingJia() > 0){
            List<String> list = StringUtils.stringToStringList(GameConfig.UNION_STORY_GRADE_ADD_SCORE, "\\|");
            String additionStr = list.get(weekData.getPingJia() - 1);
            if(!"-1".equals(additionStr)){
                List<Integer> additionValue = StringUtils.stringToIntegerList(additionStr, ";");
                //话本评级bug热更，所以try catch 了一下
                try {
                    List<Integer> sortList = StringUtils.stringToIntegerList(GameConfig.UNION_STORY_SORT, ",");
                    int degreeIndex = sortList.indexOf(weekData.getDegree());
                    addition = additionValue.get(degreeIndex);
                } catch (Exception e) {
                    getLogger().error("UnionHuaBenMgr.calPingjia error", e);
                    addition = additionValue.get(weekData.getDegree() - 1);
                }
            }
        }
        //话本结束后，记录历史评价
        if(weekData.getPingJia() > 0 && unionData != null && weekData.getCloseTime() > 0){
            Map<Integer, Integer> map = unionData.getGradeMap().get(weekData.getDegree());
            if(map == null){
                map = new HashMap<>();
                unionData.getGradeMap().put(weekData.getDegree(), map);
            }
            int num = map.getOrDefault(weekData.getPingJia(), 0);
            map.put(weekData.getPingJia(), 1 + num);
            unionData.setUpdateOption();
        }
        return addition;
    }

    /**
     * 获取通关数
     */
    public static int getPassNum(List<UnionHuaBenPass> passList) {
        int num = 0;
        for (UnionHuaBenPass pass : passList) {
            if(pass.isEnd()){
                num++;
            }
        }
        return num;
    }

    private static void addAttackRecord(long playerId, int level, CrossUnionReqContext context, int weekId, int objId, BigInteger damage, int wave, boolean kill) {
        UnionHuaBenAttackDamageData damageData = getUnionHuaBenAttackDamageData(level, context, weekId);
        List<UnionHuaBenUserAttack> attackList = damageData.getDamageMap().get(objId);
        if(attackList == null){
            attackList = new ArrayList<>();
            damageData.getDamageMap().put(objId, attackList);
        }
        UnionHuaBenUserAttack attack = null;
        for (UnionHuaBenUserAttack userAttack : attackList) {
            if(userAttack.getUserId() == playerId){
                attack = userAttack;
            }
        }
        if(attack == null) {
            attack = new UnionHuaBenUserAttack();
            attack.setServerId(context.getMember().getServerId());
            attack.setUserId(playerId);
            attackList.add(attack);
        }
        attack.setDamage(damage.add(new BigInteger(attack.getDamage())).toString());
        attack.setAttackTime(DateHelper.getCurrentSecond());
        if(kill){
            attack.getKillWaveList().add(wave);
        }
        damageData.setUpdateOption();
    }

    private static UnionHuaBenAttackDamageData getUnionHuaBenAttackDamageData(int level, CrossUnionReqContext context, int weekId) {
        UnionHuaBenAttackDamageData damageData = getUnionHuaBenAttackDamageData(weekId, context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid(), level);
        if(damageData == null){
            damageData = new UnionHuaBenAttackDamageData();
            damageData.setLevel(level);
            damageData.setWeekId(weekId);
            damageData.setUnionUid(context.getUnionInfo().getUnionUid());
            damageData.setServerId(context.getUnionInfo().getServerId());
            damageData.setInsertOption();
            addUnionHuaBenAttackDamageData(weekId, context.getUnionInfo().getServerId(), context.getUnionInfo().getUnionUid(), damageData);
        }
        return damageData;
    }

    /**
     * 计算攻击血量（造成的伤害）
     */
    private static BigInteger calAttackBlood(int idx, List<UnionHuaBenPatrons> patronsList, BigInteger blood) {
        BigInteger curBlood = new BigInteger(blood.toString());
        BigInteger damage = BigInteger.ZERO;
        for (UnionHuaBenPatrons patrons : patronsList) {
            BigInteger ability = getPatronsAbility(patrons.getAbility(), patrons.getOccupat(), patrons.getAddition(), idx);
            if(curBlood.compareTo(ability) >= 0){
                patrons.setDamage(ability.toString());
                damage = damage.add(ability);
            }else {
                patrons.setDamage(curBlood.toString());
                damage = damage.add(curBlood);
            }
            curBlood = curBlood.subtract(new BigInteger(patrons.getDamage()));
            if(curBlood.compareTo(BigInteger.ZERO) == 0){
                break;
            }
        }
        return damage;
    }

    /**
     * 门客伤害加成
     * @param addition 区服上传的已经加了  1000
     */
    private static BigInteger getPatronsAbility(String ability, int occupat, int addition, int idx) {
        //getLogger().debug("ability {}", ability);
        //getLogger().debug("addition {}", addition - 1000);
        if(idx == occupat){
            addition += GameConfig.UNION_STORY_EXTRA_ATT_PARAM;
            //getLogger().debug("克制加成 {}", GameConfig.UNION_STORY_EXTRA_ATT_PARAM);
        }
        String result = new BigDecimal(ability).multiply(BigDecimal.valueOf(addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toString();
        return new BigInteger(result);
    }

    /**
     * 是否可以进攻boss
     */
    private static boolean canAttackBoss(List<UnionHuaBenPassMonster> monsterList, int monsterWave) {
        for (UnionHuaBenPassMonster monster : monsterList) {
            if (!isMonsterDie(monsterWave, monster)) return false;
        }
        return true;
    }

    /**
     * 小怪是否被击败
     */
    private static boolean isMonsterDie(int monsterWave, UnionHuaBenPassMonster monster) {
        if("0".equals(monster.getBlood()) && monster.getWave() == monsterWave){
            return true;
        }
        return false;
    }

    /**
     * 每周话本自动结算
     */
    public static void autoWeekHuaBenSettle(){
        //周日22点后
        Calendar now = Calendar.getInstance();
        //如果是周天
        if(now.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY){
            long zeroTime = DateHelper.getTodayZeroTimeStamp();
            if(now.getTimeInMillis() >= (100 + zeroTime + GameConfig.UNION_STORY_END_TIME * DateHelper.HOUR_MILLIONS)){
                int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
                autoWeekHuaBenSettle(weekId);
            }
        }
    }

    /**
     * 结算
     */
    private static void autoWeekHuaBenSettle(int weekId){
        Map<Long, Map<String, UnionHuaBenPassWeekData>> unionMap = unionWeekDataMap.get(weekId);
        if(unionMap != null){
            for (Map.Entry<Long, Map<String, UnionHuaBenPassWeekData>> entry : unionMap.entrySet()) {
                for (Map.Entry<String, UnionHuaBenPassWeekData> dataEntry : entry.getValue().entrySet()) {
                    UnionHuaBenPassWeekData weekData = dataEntry.getValue();
                    settleWeekData(weekData);
                }
            }
        }
    }

    /**
     * 结算话本
     */
    public static void settleWeekData(UnionHuaBenPassWeekData weekData) {
        if(weekData.getCloseTime() > 0){
            return;
        }
        //结算
        weekData.setCloseTime(DateHelper.getCurrentSecond());
        UnionHuaBenUnionData unionData = getUnionHuaBenUnionData(weekData.getServerId(), weekData.getUnionUid());
        //话本评级
        int addition = calPingjia(weekData, unionData);
        CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(weekData.getUnionUid());
        //话本结束，发送邮件奖励（主要是积分）
        if(unionInfo != null && !unionInfo.isDelete()) {
            sendHuaBenEndMemberReward(unionInfo, weekData, addition);
            //榜单
            if(weekData.getLastPassTime() > 0) {
                CrossUnionWeekRank weekRank = initCrossUnionWeekRank(weekData, unionInfo);
                CrossUnionHuaBenRankMgr.changeUnionRank(weekData.getWeekId(), unionInfo.getServerId(), weekRank);
            }
        }
    }

    /**
     * 下发话本（所有成员）
     */
    public static void syncHuaBenData(CrossUnionInfo crossUnionInfo, UnionHuaBenPassWeekData weekData){
        if(weekData == null){
            int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
            weekData = getUnionHuaBenPassWeekData(weekId, crossUnionInfo.getServerId(), crossUnionInfo.getUnionUid());
        }
        UnionHuaBenProto.UnionHuaBenWeekDataSync.Builder syncMsg;
        if(weekData == null){
            syncMsg = UnionHuaBenProto.UnionHuaBenWeekDataSync.newBuilder();
            UnionHuaBenProto.UnionHuaBenBaseTemp.Builder baseBuild = UnionHuaBenProto.UnionHuaBenBaseTemp.newBuilder();
            baseBuild.setOpenTime(0);
            buildUnionHistoryHuaBenTemp(crossUnionInfo, baseBuild);
            syncMsg.setBase(baseBuild);
        }else {
            syncMsg = buildHuaBenSyncData(crossUnionInfo, weekData);
        }
        Map<Long, CrossUnionMember> memberMap = CrossUnionMgr.getUnionMemberMap(crossUnionInfo.getUnionUid());
        if(memberMap != null) {
            for (Map.Entry<Long, CrossUnionMember> entry : memberMap.entrySet()) {
                MessageHelper.sendPacket(entry.getValue().getServerId(), entry.getValue().getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_SYNC, syncMsg));
            }
        }
    }

    /**
     * 下发话本
     */
    public static void syncHuaBenData(CrossUnionInfo crossUnionInfo, CrossUnionMember member, UnionHuaBenPassWeekData weekData){

        if(weekData == null){
            int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
            weekData = getUnionHuaBenPassWeekData(weekId, crossUnionInfo.getServerId(), crossUnionInfo.getUnionUid());
        }
        if(weekData == null){
            UnionHuaBenProto.UnionHuaBenWeekDataSync.Builder syncMsg = UnionHuaBenProto.UnionHuaBenWeekDataSync.newBuilder();
            UnionHuaBenProto.UnionHuaBenBaseTemp.Builder baseBuild = UnionHuaBenProto.UnionHuaBenBaseTemp.newBuilder();
            baseBuild.setOpenTime(0);
            buildUnionHistoryHuaBenTemp(crossUnionInfo, baseBuild);
            syncMsg.setBase(baseBuild);
            MessageHelper.sendPacket(member.getServerId(), member.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_SYNC, syncMsg));
        }else {
            UnionHuaBenProto.UnionHuaBenWeekDataSync.Builder syncMsg = buildHuaBenSyncData(crossUnionInfo, weekData);
            MessageHelper.sendPacket(member.getServerId(), member.getUserId(), YanQuMessageUtils.buildMessage(Protocol.U_CROSS_UNION_HUA_BEN_SYNC, syncMsg));
        }
    }

    /**
     * 榜单数据
     */
    public static Map<Integer, Map<Integer, Map<Integer, LinkedList<CrossUnionWeekRank>>>> buildWeekRank(){
        int thisWeekId = CrossUnionHuaBenRankMgr.getThisWeekId();
        Map<Integer, Map<Integer, Map<Integer, LinkedList<CrossUnionWeekRank>>>> result = new HashMap<>();
        int now = DateHelper.getCurrentSecond();
        for (Map.Entry<Integer, Map<Long, Map<String, UnionHuaBenPassWeekData>>> entry : unionWeekDataMap.entrySet()) {
            int weekId = entry.getKey();
            if(result.get(weekId) == null){
                result.put(weekId, new HashMap<>());
            }
            Map<Integer, Map<Integer, LinkedList<CrossUnionWeekRank>>> groupMap = result.get(weekId);
            for (Map.Entry<Long, Map<String, UnionHuaBenPassWeekData>> mapEntry : entry.getValue().entrySet()) {

                int groupId;
                if(thisWeekId  == weekId){
                    groupId = UnionHuaBenServerGroupMgr.getGroupIdByServerId(mapEntry.getKey());
                }else {
                    groupId = CrossUnionHuaBenRankMgr.getWeekServerGroup(weekId, mapEntry.getKey());
                }

                if(groupMap.get(groupId) == null){
                    groupMap.put(groupId, new HashMap<>());
                }
                Map<Integer, LinkedList<CrossUnionWeekRank>> typeMap = groupMap.get(groupId);
                for (Map.Entry<String, UnionHuaBenPassWeekData> dataEntry : mapEntry.getValue().entrySet()) {
                    UnionHuaBenPassWeekData data = dataEntry.getValue();
                    if(data.getLastPassTime() <= 0){
                        continue;
                    }
                    int type = data.getDegree();
                    if(typeMap.get(type) == null){
                        typeMap.put(type, new LinkedList<>());
                    }
                    CrossUnionWeekRank rank = new CrossUnionWeekRank();
                    rank.setType(type);
                    rank.setValue(BigInteger.valueOf(getPassNum(data.getPassList())));
                    CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(data.getUnionUid());
                    if(unionInfo != null){
                        rank.setServerId(unionInfo.getServerId());
                        rank.setUnionBaseInfo(CrossUnionMgr.parseUnionBaseInfo(unionInfo));
                    }
                    if(unionInfo != null && unionInfo.isDelete()){
                        continue;
                    }
                    rank.setWeekId(weekId);
                    rank.setParam("" + calHuaBenPassTime(now, data));
                    rank.setUnionUid(data.getUnionUid());
                    typeMap.get(type).add(rank);
                }
            }
        }
        return result;
    }

    /**
     * 计算话本准确的过关时间
     */
    public static int calHuaBenPassTime(int now, UnionHuaBenPassWeekData data) {
        if(data.getLastPassTime() > 0){
            return data.getLastPassTime() - data.getOpenTime();
        }else {
            if(data.getCloseTime() > 0){
                return data.getCloseTime() - data.getOpenTime();
            }else {
                return now - data.getOpenTime();
            }
        }
    }

    public static void addGuanPuRewardRecord(long serverId, UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp recordTemp){

        int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
        int groupId = UnionHuaBenServerGroupMgr.getGroupIdByServerId(serverId);
        Map<Integer, List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp>> groupMap = guanPuRecordMap.get(weekId);
        if(groupMap == null){
            synchronized (guanPuRecordMap){
                groupMap = guanPuRecordMap.get(weekId);
                if(groupMap == null){
                    guanPuRecordMap.put(weekId, new ConcurrentHashMap());
                }
            }
            groupMap = guanPuRecordMap.get(weekId);
        }

        List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp> list = groupMap.get(groupId);
        if(list == null){
            synchronized (groupMap){
                list = groupMap.get(groupId);
                if(list == null){
                    groupMap.put(groupId, new ArrayList<>());
                }
            }
            list = groupMap.get(groupId);
        }
        synchronized (list){
            if(list.size() >= 50){
                list.remove(0);
            }
            list.add(recordTemp);
        }
    }

    public static List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp> getGuanPuRewardRecord(long serverId){

        int weekId = CrossUnionHuaBenConfigMgr.getThisWeekId();
        Map<Integer, List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp>> groupMap = guanPuRecordMap.get(weekId);
        if(groupMap == null){
            return new ArrayList<>();
        }
        int groupId = UnionHuaBenServerGroupMgr.getGroupIdByServerId(serverId);
        List<UnionHuaBenProto.UnionHuaBenGuanPuHistoryRecordTemp> result = groupMap.get(groupId);
        if(result == null){
            result = new ArrayList<>();
        }
        return result;

    }

    private static UnionHuaBenProto.UnionHuaBenWeekDataSync.Builder buildHuaBenSyncData(CrossUnionInfo crossUnionInfo, UnionHuaBenPassWeekData weekData) {

        UnionHuaBenProto.UnionHuaBenWeekDataSync.Builder syncMsg = UnionHuaBenProto.UnionHuaBenWeekDataSync.newBuilder();

        UnionHuaBenProto.UnionHuaBenBaseTemp.Builder baseBuilder = buildHuaBenBaseTemp(crossUnionInfo, weekData);

        for(UnionHuaBenProto.UnionHuaBenLevelDetailTemp.Builder builder : buildHuaBenLevelDetail(weekData)){
            syncMsg.addDetail(builder);
        }

        syncMsg.setBase(baseBuilder);

        return syncMsg;
    }

    private static List<UnionHuaBenProto.UnionHuaBenLevelDetailTemp.Builder> buildHuaBenLevelDetail(UnionHuaBenPassWeekData weekData) {
        List<UnionHuaBenProto.UnionHuaBenLevelDetailTemp.Builder> builderList = new ArrayList<>();
        for (UnionHuaBenPass benPass : weekData.getPassList()) {
            UnionHuaBenProto.UnionHuaBenLevelDetailTemp.Builder detailBuilder = UnionHuaBenProto.UnionHuaBenLevelDetailTemp.newBuilder();

            UnionHuaBenProto.UnionHuaBenLevelBossData.Builder bossBuild = UnionHuaBenProto.UnionHuaBenLevelBossData.newBuilder();
            bossBuild.setBlood(benPass.getBlood());
            detailBuilder.setBoss(bossBuild);

            for (UnionHuaBenPassMonster monster : benPass.getMonsterList()) {
                UnionHuaBenProto.UnionHuaBenLevelMonsterData.Builder monsterBuild = UnionHuaBenProto.UnionHuaBenLevelMonsterData.newBuilder();
                monsterBuild.setBlood(monster.getBlood());
                monsterBuild.setWave(monster.getWave());
                monsterBuild.setOccupation(monster.getOccupat());
                detailBuilder.addMonster(monsterBuild);
            }
            builderList.add(detailBuilder);
        }
        return builderList;
    }

    private static UnionHuaBenProto.UnionHuaBenBaseTemp.Builder buildHuaBenBaseTemp(CrossUnionInfo crossUnionInfo, UnionHuaBenPassWeekData weekData) {
        UnionHuaBenProto.UnionHuaBenBaseTemp.Builder baseBuilder = UnionHuaBenProto.UnionHuaBenBaseTemp.newBuilder();
        baseBuilder.setOpenTime(weekData.getOpenTime());
        baseBuilder.setDegree(weekData.getDegree());
        baseBuilder.setPingJia(weekData.getPingJia());
        baseBuilder.setCloseTime(weekData.getCloseTime());
        baseBuilder.setLastPassTime(weekData.getLastPassTime());
        baseBuilder.setDuration(weekData.getDuration());
        buildUnionHistoryHuaBenTemp(crossUnionInfo, baseBuilder);

        //配置
        Map<Integer, UnionHuaBenBaseTempData> benBaseTempDataMap = CrossUnionHuaBenConfigMgr.getWeekServerTempData(weekData.getWeekId(), crossUnionInfo.getServerId(), weekData.getDegree());
        if(benBaseTempDataMap != null) {
            for (int i = 0; i < weekData.getPassList().size(); i++) {
                UnionHuaBenPass benPass = weekData.getPassList().get(i);
                UnionHuaBenBaseTempData baseTempData = benBaseTempDataMap.get(i + 1);
                if(baseTempData != null) {
                    UnionHuaBenProto.UnionHuaBenLevelBaseTemp.Builder builder = UnionHuaBenProto.UnionHuaBenLevelBaseTemp.newBuilder();
                    builder.setJinDu(calPassJinDu(baseTempData, benPass));
                    builder.setPass(benPass.isEnd());
                    baseBuilder.addLevel(builder);
                }
            }
        }

        return baseBuilder;
    }

    private static void buildUnionHistoryHuaBenTemp(CrossUnionInfo crossUnionInfo, UnionHuaBenProto.UnionHuaBenBaseTemp.Builder baseBuilder) {
        UnionHuaBenUnionData unionData = getUnionHuaBenUnionData(crossUnionInfo.getServerId(), crossUnionInfo.getUnionUid());
        if(unionData != null){
            UnionHuaBenProto.UnionHistoryHuaBenTemp.Builder builder = UnionHuaBenProto.UnionHistoryHuaBenTemp.newBuilder();
            for (Map.Entry<Integer, Map<Integer, Integer>> entry : unionData.getGradeMap().entrySet()) {
                UnionHuaBenProto.UnionHistoryHuaBenDegreeTemp.Builder degreeBuild = UnionHuaBenProto.UnionHistoryHuaBenDegreeTemp.newBuilder();
                degreeBuild.setDegree(entry.getKey());
                for (Map.Entry<Integer, Integer> pingjia : entry.getValue().entrySet()) {
                    UnionHuaBenProto.UnionHistoryHuaBenGradeTemp.Builder gradeBuild = UnionHuaBenProto.UnionHistoryHuaBenGradeTemp.newBuilder();
                    gradeBuild.setGrade(pingjia.getKey());
                    gradeBuild.setTimes(pingjia.getValue());
                    degreeBuild.addGrade(gradeBuild);
                }
                builder.addDegree(degreeBuild);
            }
            baseBuilder.setHistory(builder);
        }
    }

    /**
     * 计算话本进度
     */
    private static int calPassJinDu(UnionHuaBenBaseTempData baseTempData, UnionHuaBenPass benPass) {
        BigInteger totalBlood = new BigInteger(baseTempData.getBossHP());
        BigInteger totalMonsterBlood = new BigInteger(baseTempData.getMonsterHP());
        totalMonsterBlood = totalMonsterBlood.multiply(BigInteger.valueOf(baseTempData.getMonsterWave() * 5));
        totalBlood = totalBlood.add(totalMonsterBlood);

        BigInteger blood = new BigInteger(benPass.getBlood());
        for (UnionHuaBenPassMonster monster : benPass.getMonsterList()) {
            BigInteger monsterBlood = new BigInteger(monster.getBlood());
            monsterBlood = monsterBlood.add(new BigInteger(baseTempData.getMonsterHP()).multiply(BigInteger.valueOf((baseTempData.getMonsterWave() - monster.getWave()))));
            blood = blood.add(monsterBlood);
        }

        int jinDu = new BigDecimal(totalBlood.subtract(blood).multiply(BigInteger.valueOf(100))).divide(new BigDecimal(totalBlood), 0, BigDecimal.ROUND_UP).intValue();
        return jinDu;
    }

}
